<Serializable()> _
Public Class SelectQuery
    Inherits Query
    Implements ICriteriaContainer

    Protected mTableName As String
    Protected mFields As List(Of String)
    Protected mCriteria As CriteriaGroup
    Protected mOrderBy As String
    Protected mGroupBy As New List(Of String)
    Protected mHaving As New List(Of String)
    Protected mJoins As New List(Of JoinInfo)

    Public ReadOnly Property GroupBy() As List(Of String)
        Get
            Return mGroupBy
        End Get
    End Property

    Public ReadOnly Property Having() As List(Of String)
        Get
            Return mHaving
        End Get
    End Property

    Public Property OrderBy() As String
        Get
            Return mOrderBy
        End Get
        Set(ByVal value As String)
            mOrderBy = value
        End Set
    End Property

    Public Property TableName() As String
        Get
            Return mTableName
        End Get
        Set(ByVal value As String)
            mTableName = value
        End Set
    End Property

    Public ReadOnly Property Fields() As List(Of String)
        Get
            Return mFields
        End Get
    End Property

    Public Overrides Function GetSQLText(Options As QueryOptions) As String
        Dim Space As String = If(Options.CompressSpaces, "", " ")
        Dim ret As String = "SELECT "
        ret &= String.Join("," & Space, mFields.ToArray)
        ret &= " FROM " & mTableName

        If mJoins.Count > 0 Then
            For Each Join As JoinInfo In mJoins
                ret &= " " & Join.GetText(Options)
            Next
        End If

        If mCriteria.ShouldRender Then
            ret &= " WHERE "
            mCriteria.RenderParens = False
            ret &= mCriteria.GetText(Options)
        End If

        If mGroupBy.Count > 0 Then
            ret &= " GROUP BY "
            ret &= String.Join(", ", mGroupBy.ToArray)
        End If
        If mHaving.Count > 0 Then
            ret &= " HAVING "
            ret &= String.Join(" AND ", mHaving.ToArray)
        End If
        If mOrderBy <> "" Then
            ret &= " ORDER BY " & OrderBy
        End If
        If Options.TerminateQuery Then ret &= ";"
        Return ret
    End Function

    Public Sub New()
        mFields = New List(Of String)
        'mGroupBy = New List(Of String)
        mCriteria = New CriteriaGroup(True)
        mJoins = New List(Of JoinInfo)
    End Sub

    Public Sub New(Table As String)
        Me.New()
        mTableName = Table
    End Sub

    Public Sub AddCriteria(ByVal Criteria As ICriteriaComponent) Implements ICriteriaContainer.AddCriteria
        mCriteria.AddCriteria(Criteria)
    End Sub
    Public Sub AddCriteria(ByVal Criteria As IEnumerable(Of ICriteriaComponent)) Implements ICriteriaContainer.AddCriteria
        For Each Crit As ICriteriaComponent In Criteria
            AddCriteria(Crit, BooleanOperator.[Default])
        Next
    End Sub
    Public Sub AddCriteria(ByVal Criteria As ICriteriaComponent, ByVal Op As BooleanOperator) Implements ICriteriaContainer.AddCriteria
        mCriteria.AddCriteria(Criteria, Op)
    End Sub
    Public Function AddCriteria(LeftExpression As String, CriteriaOp As Operation, RightExpression As String) As Criteria Implements ICriteriaContainer.AddCriteria
        Return mCriteria.AddCriteria(LeftExpression, CriteriaOp, RightExpression)
    End Function
    Public Function AddCriteria(LeftExpression As String, CriteriaOp As Operation, RightExpression As String, Op As BooleanOperator) As Criteria Implements ICriteriaContainer.AddCriteria
        Return mCriteria.AddCriteria(LeftExpression, CriteriaOp, RightExpression, Op)
    End Function

    Public Sub RemoveCriteria(Criteria As ICriteriaComponent)
        mCriteria.RemoveCriteria(Criteria)
    End Sub

    Public Function AddJoin(Table As String, LeftExpression As String, CriteriaOp As Operation, RightExpression As String) As JoinInfo
        Dim ret As New JoinInfo(Table, LeftExpression, CriteriaOp, RightExpression)
        Me.mJoins.Add(ret)
        Return ret
    End Function

    Public Sub AddJoin(Join As JoinInfo)
        Me.mJoins.Add(Join)
    End Sub

    Public Sub AddFields(Fields As IEnumerable(Of String))
        mFields.AddRange(Fields)
    End Sub

    Public ReadOnly Property CriteriaCount As Integer Implements ICriteriaContainer.CriteriaCount
        Get
            Return mCriteria.CriteriaCount
        End Get
    End Property

    Public Property RenderParens As Boolean Implements ICriteriaContainer.RenderParens
        Get
            Return False
        End Get
        Set(value As Boolean)
            'Ignore the value
        End Set
    End Property

    Public Function Criteria() As System.Collections.Generic.IEnumerable(Of ICriteriaComponent) Implements ICriteriaContainer.Criteria
        Return mCriteria.Criteria
    End Function

    Public Sub ClearCriteria() Implements ICriteriaContainer.ClearCriteria
        mCriteria.ClearCriteria()
    End Sub
End Class
